package com.example.websocketproject.service;

import com.example.websocketproject.domain.MsgDomin;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author 吴 da ~
 * @data 2021/3/4 9:48
 */

/**
 *
 * @ServerEndpoint 这个注解有什么作用？
 *
 * 这个注解用于标识作用在类上，它的主要功能是把当前类标识成一个WebSocket的服务端
 * 注解的值用户客户端连接访问的URL地址
 *
 */

@Component
@ServerEndpoint("/websocket/{name}")
@Slf4j
public class websocket {


    /**
     *  与某个客户端的连接对话，需要通过它来给客户端发送消息
     */
    private Session session;

    /**
     * 标识当前连接客户端的用户名
     */
    private String name;

    /**
     *  用于存所有的连接服务的客户端，这个对象存储是安全的
     */
//    private static ConcurrentHashMap<String, websocket> webSocketSet = new ConcurrentHashMap<String, websocket>();

    private static final Map<String, Set<Session>> rooms = new ConcurrentHashMap();

    @OnOpen
    public void OnOpen(Session session, @PathParam(value = "name") String name){
//        this.session = session;
//        this.name = name;
//        // name是用来表示唯一客户端，如果需要指定发送，需要指定发送通过name来区分
//        webSocketSet.put(name,this);
        // 将session按照房间名来存储，将各个房间的用户隔离
        if (!rooms.containsKey(name)) {
            // 创建房间不存在时，创建房间
            Set<Session> room = new HashSet<>();
            // 添加用户
            room.add(session);
            rooms.put(name, room);
        } else {
            // 房间已存在，直接添加用户到相应的房间
            rooms.get(name).add(session);
        }
        log.info("[WebSocket] 连接成功，当前房间数为：={}",rooms.size());
    }


    @OnClose
    public void OnClose(@PathParam("name") String name, Session session) throws IOException {
        rooms.get(name).remove(session);
//        rooms.remove(name);
        int i = 0;
        for (Session session1 : rooms.get(name)) {
            i++;
        }
        AppointSending(name,i);
        log.info("[WebSocket] 退出成功，当前连接人数为：={}",rooms.size());
    }

    @OnMessage
    public void OnMessage(@PathParam("name") String name,
                          String message, Session session) throws Exception {
        log.info("[WebSocket] 收到消息：{}",message);
        //判断是否需要指定发送，具体规则自定义
//        if(message.indexOf("TOUSER") == 0){
//            String name = message.substring(message.indexOf("TOUSER")+6,message.indexOf(";"));
//            AppointSending(name,message.substring(message.indexOf(";")+1,message.length()));
//        }else{
//            GroupSending(message);
//        }
        // 此处应该有html过滤
        Gson gson = new Gson();
        MsgDomin bdPushID2 = gson.fromJson(message, MsgDomin.class);
        bdPushID2.setType(session.getId());
        if (bdPushID2.getName() == null){
            bdPushID2.setName(randomName());
        }

        System.out.println(session);

        System.out.println(message);
        // 接收到信息后进行广播
        broadcast(name, bdPushID2);
    }
    // 按照房间名进行广播
    public void broadcast(String roomName, MsgDomin msg) throws Exception {
//        sendMsg(roomName,msg)
        Gson gson = new Gson();
        int i = 0;
        for (Session session : rooms.get(roomName)) {
            i++;
            msg.setNum(i);
            session.getBasicRemote().sendText(gson.toJson(msg));
        }
        AppointSending(roomName,i);
    }



    /**
     * 群发
     * @param message
     */
//    public void GroupSending(String message){
//        for (String name : rooms.keySet()){
//            try {
//                rooms.get(name).session.getBasicRemote().sendText(message);
//            }catch (Exception e){
//                e.printStackTrace();
//            }
//        }
//    }

    /**
     * 指定发送
     * @param name
     * @param message
     */
    public void AppointSending(String name, int message) throws IOException {
        MsgDomin msgDomin = new MsgDomin();
        msgDomin.setMsg("xxx");
        msgDomin.setNum(message);
        Gson gson = new Gson();
        for (Session session : rooms.get(name)) {
            session.getBasicRemote().sendText(gson.toJson(msgDomin));
        }
//        try {
//            rooms.get(name).getBasicRemote().sendText(message);
//        }catch (Exception e){
//            e.printStackTrace();
//        }
    }

    //随机姓名
    private String randomName() {
        Random random = new Random();
        String str = "";
        int hightPos, lowPos;
        for (int i = 0; i < 3; ++i) {
            hightPos = (176 + Math.abs(random.nextInt(39)));
            lowPos = (161 + Math.abs(random.nextInt(93)));
            byte[] b = new byte[2];
            b[0] = (Integer.valueOf(hightPos)).byteValue();
            b[1] = (Integer.valueOf(lowPos)).byteValue();
            try {
                str += new String(b, "GB2312");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return str;
    }

//    private int i;
//    @Scheduled(cron = "*/15 * * * * ?")
//    public void execute() {
//        log.info("thread id:{},FixedPrintTask execute times:{}", Thread.currentThread().getId(), ++i);
//    }

}
